package github.ziwukun.jsonql.analysis;

import java.util.List;

import github.ziwukun.jsonql.lang.CmpOpr;
import github.ziwukun.jsonql.lang.JSONQL;
import github.ziwukun.jsonql.lang.Where;
import github.ziwukun.jsonql.orm.FieldProp;
import github.ziwukun.jsonql.orm.Model;
import github.ziwukun.jsonql.orm.ModelProp;
import github.ziwukun.jsonql.orm.Prop;

public class ModelAndWhereAnalysistor implements ModelAndQLAnalysistor{
	
	@Override
	public void analysis(Model model, JSONQL ql) throws AnalysisException {
		Where where = ql.where();
		if(where != null) {
			analysisModelAndWhere(model,where);
		}
	}
	
	private void analysisModelAndWhere(Model model,Where where) {
		if(where.keyIsProp()) {
			String wherePropName = where.keyAsProp();
			Prop prop = model.getPropByName(wherePropName);
			if(prop == null) {
				throw new AnalysisException("错误的@where语句\n{}",where.toJSONQL());
			}
			analysisPropAndWhere(prop,where);
		}
		else if(where.keyIsLogic()) {
			List<Where> wheres = where.valAsWheres();
			for (Where childWhere : wheres) {
				String wherePropName = childWhere.keyAsProp();
				Prop prop = model.getPropByName(wherePropName);
				if(prop == null) {
					throw new AnalysisException("错误的@where语句\n{}",where.toJSONQL());
				}
				analysisPropAndWhere(prop,childWhere);
			}
		}
		else {
			throw new AnalysisException("错误的@where语句\n{}",where.toJSONQL());
		}
	}
	
	private void analysisPropAndWhere(Prop prop,Where propWhere) {
		// 容器属性
		if(prop instanceof FieldProp) {
			FieldProp hasChildProp = (FieldProp)prop;
			// 只有叶子节点属性才能参数比较 没有子属性就是叶子属性
			if(hasChildProp.isChildPropsEmpty()) {
				// 叶子节点的where值 一定是比较符 + 比较值
				if(!propWhere.valAsWhere().keyIsCmpOpr()) {
					throw new AnalysisException("错误的@where语句\n{}",propWhere.toJSONQL());
				}
				CmpOpr cs = propWhere.valAsWhere().keyAsCmpOpr();
				// 不支持的比较符
				if(!prop.support(cs)) {
					throw new AnalysisException("错误的@where语句\n{},不支持的比较符{}",
						propWhere.toJSONQL(),cs.atWord());
				}
			}
			// 非叶子节点，递归到叶子节点并检验
			else {
				for (FieldProp childProp : hasChildProp.childProps()) {
					Where childPropWhere = propWhere.childPropWhere(childProp.propName());
					if(childPropWhere != null) {
						analysisPropAndWhere((Prop)childProp,childPropWhere);
					}
				}
			}
		}
		else if(prop instanceof ModelProp) {
			ModelProp modelProp = (ModelProp)prop;
			analysisModelAndWhere(modelProp.propModel(),propWhere.valAsWhere());
		}
	}
}
